共计6127个字符,预计需要花费16分钟才能阅读完成。
下载地址
开源地址:https://github.com/mcdudu233/FileSystem.git
下载地址:https://github.com/mcdudu233/FileSystem/releases/tag/exe
代码设计
1. 先设计好 FCB 的结构和目录项的结构
class file {
private:
/* 基本信息 */
string name; // * 关键字:文件名
string father; // 所属的目录名
vector<int> point;// 所有数据块的指针
/* 存取控制 */
int master; // 所属用户
char masterPrivilege;// 主用户权限
char otherPrivilege; // 其他用户权限
/* 使用信息 */
int size; // 大小
chrono::system_clock::time_point createTime;// 创建时间
chrono::system_clock::time_point modifyTime;// 修改时间
我们根据 cpp 类的特性,将 FCB 简化成一个 file 类,其中包含 FCB 的基本信息、存取控制信息和使用信息,以文件名为关键字。同时,我们采取的是单级索引组织方式,因此设定了所有数据块的指针数组。
对于目录也是一个道理,我们将目录项分为子目录和文件分开保存,关键字为目录名:
class directory {
private:
/* 基本信息 */
string name; // * 关键字:目录名
string father; // 父目录的目录名
vector<directory> directories;// 目录下的子目录
vector<file> files; // 目录下的文件
/* 存取控制 */
int master = user_root.getUid();// 所属用户
char masterPrivilege; // 所有者权限
char otherPrivilege; // 其他人权限
/* 使用信息 */
chrono::system_clock::time_point createTime;// 创建时间
chrono::system_clock::time_point modifyTime;// 修改时间
对于用户,我们同样设立一个类进行管理:
class user {
private:
int uid; // * 关键字:用户 uid
string name; // 用户名
string password;// 用户密码 采用 MD5 加密
bool superuser; // 是否是超级用户
2. 完善每一个类的方法和属性
file(文件)类:
public:
file();
file(const string &fileName, string father, int master);
file(const file &file);
~file();
bool operator==(const file &other);
public:
string getName(); // 获取用户名
bool setName(string name);// 设置用户名
int getSize(); // 获取文件大小
/* 文件操作 */
bool clearFile(); // 清空所有文件内容
char *readFile(); // 读取的文件内容
bool writeFile(char *data, int size);// 写入文件内容
/* 存取控制 */
int getUser(); // 获取用户
bool setUser(int uid); // 设置用户
bool setMasterPrivilege(char masterPrivilege); // 设置文件所有者权限
bool setOtherPrivilege(char otherPrivilege); // 设置其他用户的权限
bool hasMasterPrivilege_read(char masterPrivilege); // 判断所有者是否有读取权限
bool hasMasterPrivilege_write(char masterPrivilege); // 判断所有者是否有写入权限
bool hasMasterPrivilege_execute(char masterPrivilege);// 判断所有者是否有执行权限
bool hasOtherPrivilege_read(char otherPrivilege); // 判断其他用户是否有读取权限
bool hasOtherPrivilege_write(char otherPrivilege); // 判断其他用户是否有写入权限
bool hasOtherPrivilege_execute(char otherPrivilege); // 判断其他用户是否有执行权限
/* 使用信息 */
chrono::system_clock::time_point getCreateTime();// 获取创建时间
chrono::system_clock::time_point getModifyTime();// 获取修改时间
/* 序列化 */
void serialize(fstream &out) const;// 序列化
void deserialize(fstream &in); // 反序列化
directory(文件夹)类:
public:
directory();
directory(string name, string father, int master);
directory(const directory &dir);
~directory();
bool operator==(const directory &other);
public:
string getName(); // 获取目录名
bool setName(string name); // 设置用户名
string getFather(); // 获取父目录名
bool setFather(string father);// 设置父目录名
/* 目录操作 */
vector<directory> *getDirectories(); // 获取所有子目录
vector<file> *getFiles(); // 获取所有文件
bool addFile(file file); // 新增文件
bool addDirectory(directory dir); // 新增目录
bool removeFile(string name); // 删除文件
bool removeDirectory(string name); // 删除目录
file *getFile(string name); // 根据名字获取文件 没有返回 nullptr
directory *getDirectory(string name);// 根据名字获取目录 没有返回 nullptr
bool has(string name); // 目录中有这个文件 (目录或者文件)
bool hasFile(string name); // 目录中有这个文件
bool hasDirectory(string name); // 目录中有这个目录
/* 存取控制 */
int getUser(); // 获取所属用户
bool setUser(int uid); // 设置所属用户
char getMasterPrivilege(); // 获取所有者权限
char getOtherPrivilege(); // 获取其他用户权限
bool hasMasterPrivilege_read(char masterPrivilege); // 判断所有者是否有读取权限
bool hasMasterPrivilege_write(char masterPrivilege); // 判断所有者是否有写入权限
bool hasMasterPrivilege_execute(char masterPrivilege);// 判断所有者是否有执行权限
bool hasOtherPrivilege_read(char otherPrivilege); // 判断其他用户是否有读取权限
bool hasOtherPrivilege_write(char otherPrivilege); // 判断其他用户是否有写入权限
bool hasOtherPrivilege_execute(char masterPrivilege); // 判断其他用户是否有执行权限
/* 使用信息 */
chrono::system_clock::time_point getCreateTime();// 获取创建时间
chrono::system_clock::time_point getModifyTime();// 获取修改时间
/* 序列化 */
void serialize(fstream &out) const;// 序列化
void deserialize(fstream &in); // 反序列化
};
// 根目录
extern directory dir_root;
user(用户)类:
public:
user();
user(int uid, string name, string password = "", bool superuser = false);
~user();
bool operator==(const user &other);
public:
int getUid(); // 获取 UID
string getName(); // 获取用户名
bool setName(string name); // 设置用户名
string getPassword(); // 获取用户密码 MD5
bool setPassword(string password); // 设置用户密码
bool checkPassword(string password);// 检测密码是否一致
bool getSuper(); // 判断是否为超级用户
bool setSuper(bool super); // 设置是否为超级用户
/* 序列化 */
void serialize(fstream &out) const;// 序列化
void deserialize(fstream &in); // 反序列化
};
// 默认用户
extern user user_root;
3. 数据处理的方法
我们采用单文件来保存数据,即用后缀“.hwh.xb.fs”的文件来保存我们自制的文件系统:
namespace fs = std::filesystem;
// 文件系统数据的存放路径
#define DATA_PATH "./"
#define DATA_SUFFIX ".hwh.xb.fs"
bool initData(const string &name);
bool closeData();
bool existData(const string &name);
bool setAvailable(vector<bool> *v, int start);
int getSpaceSize();
bool setSpaceSize(int size);
int getBlockSize();
bool setBlockSize(int size);
bool setPosition(int block);// 设置读写指针位置
fstream &getData(); // 获取 file
/* 文件数据读写方法 */
bool hasBlock(int block); // 判断块是否已经有数据了
int availableBlock(); // 获取空闲块
bool useBlock(int block); // 使用空闲块
bool releaseBlock(int block); // 释放已经使用的块
char *readBlock(int block); // 读取某一块
bool writeBlock(int block, char *data, int size);// 写入某一块
#endif//FILESYSTEM_DATA_H
接着测试读写的方法,初始化文件内容为 16 进制的全 0,这里我们采用 winhex 软件来测试查看:
测试无误,数据初始化为全 0。
4. 完成文件系统(filesystem)类
该类用于调用并实现文件系统操作,要用到前面所有的类。
首先包含一个文件系统应有的私有属性:
private:
vector<string> current;// 当前所在的路径
string name; // 文件系统数据的文件名
int space_size; // 空间大小
int block_size; // 块大小
int block_data; // 开始存数据部分的块地址
user *user_current;// 当前操作系统的用户
vector<user> users;// 所有用户
directory tree; // 根目录
vector<bool> available;// 空闲盘块 位视图法
在这里我们采用位示图法保存空闲盘块的数据,因为这种方法简单且有效,修改效率高。
接着我们完成文件系统可能用到的所有操作:
public:
/* 基本 */
string getCurrentPath(); // 获取当前所在的路径
directory *getTree(); // 获取树形目录
directory *getFatherByName(directory dir);// 根据目录找到父目录
directory *getFatherByName(file f); // 根据文件找到父目录
directory *findParentDirectory(directory *current, directory &target);
directory *findParentDirectory(directory *current, file &target);
/* 命令 */
bool ls(vector<List> &v); // 列出当前文件夹下的文件
bool ls(string path, vector<List> &v); // 列出某个文件夹下的文件
int disk(bool left); // 获取磁盘容量 (left 为 true 时返回剩余容量)
bool cd(string path); // 跳转到某个文件夹
bool mkdir(directory d, const string &dname); // 新建文件夹
bool touch(directory d, const string &fname); // 新建文件
bool rm(file f); // 删除文件
bool rm(directory d); // 删除目录
vector<user> usrs(); // 获取所有用户
int useradd(string name, string password = "", bool super = false); // 新增用户
bool userdel(int uid); // 删除用户
bool usercrg(int uid, string name, string password = "", bool super = false);// 修改用户信息
user userbyid(int uid); // 根据 uid 查找用户
再接下来就是测试我们的文件系统类了,我们尝试初始化该类并写入了一些文件和文件夹信息:
很明显文件结构被写入到该文件的首部(我们的文件系统默认分配一定的首部空间写入文件结构信息)
界面设计
界面
(1)格式化窗口设计
(2)登录界面设计
(3)主界面设计
(4)右键菜单
(5)文本编辑界面
(6)顶部功能菜单
界面代码
界面代码请查看源代码,这里不占用宝贵的空间进行赘述了。
结果
分析后共 3689 行代码。